package com.google.code.coma.gui;

import com.google.code.coma.Coma;
import com.google.code.coma.domain.*;
import com.google.code.coma.gui.dialog.*;
import com.google.code.coma.gui.rmi.RMIComputerDataProvider;
import com.google.code.coma.gui.rmi.RMIOrderDataProvider;
import com.google.code.coma.gui.rmi.RMIPartDataProvider;
import com.google.code.coma.gui.space.SpaceComputerDataProvider;
import com.google.code.coma.gui.space.SpaceOrderDataProvider;
import com.google.code.coma.gui.space.SpacePartDataProvider;
import com.google.code.coma.gui.util.ImageUtil;
import com.google.code.coma.gui.worker.WorkerManager;
import com.google.com.coma.tester.CompletenessTester;
import com.google.com.coma.tester.DefectTester;
import com.google.com.coma.tester.Tester;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.BlendMode;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Reflection;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author Dominik Strasser, dominikstr@gmail.com
 */
public class ManagementGUI extends Application {

	private WorkerManager.Mode operationMode = WorkerManager.Mode.SPACE;

	private String factoryId;

	@Override
	public void start(final Stage stage) throws Exception {
		if (getParameters().getRaw().size() != 2) {
			System.out.println("You have to provider the operation mode and the factory id");
			System.exit(0);
		}
		try {
			operationMode = WorkerManager.Mode.valueOf(getParameters().getRaw().get(0));
		} catch (Exception e) {
			System.out.println("Invalid operation mode parameter: " + getParameters().getRaw().get(0));
			System.exit(0);
		}
		try {
			factoryId = getParameters().getRaw().get(1);
		} catch (Exception e) {
			System.out.println("Invalid factoryid parameter: " + getParameters().getRaw().get(1));
			System.exit(0);
		}
		stage.setTitle("SBC::COMA - Management GUI. Factory: " + factoryId);
		stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
			@Override
			public void handle(WindowEvent windowEvent) {
				WorkerManager.stop();
				System.exit(0);
			}
		});
		BorderPane border = new BorderPane();
		Scene scene = new Scene(border, 1000, 650, Color.TRANSPARENT);
		stage.setScene(scene);

		HBox hbox = new HBox();
		hbox.setAlignment(Pos.CENTER);
		hbox.setPadding(new Insets(15, 12, 15, 12));
		hbox.setSpacing(10);
		hbox.setStyle("-fx-background-color: #336699");

		Button createProducer = new Button("Create Producer");
		createProducer.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent actionEvent) {
				new ProducerConfigurationDialog(operationMode, factoryId).show();
			}
		});

		Button createAssemblyWorker = new Button("Create Assembly Worker");
		createAssemblyWorker.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				WorkerManager.createWorker(WorkerManager.WorkerType.ASSEMBLY, operationMode, factoryId);
			}
		});
		Button createCompletnessTester = new Button("Create Completness Tester");
		createCompletnessTester.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				Class[] argumentTypes = {String.class, Tester.class, LifeCycleStep.class};
				WorkerManager.createWorker(WorkerManager.WorkerType.TESTER, operationMode, argumentTypes, factoryId, new CompletenessTester(), LifeCycleStep.CREATED);
			}
		});
		Button createDefectTester = new Button("Create Defect Tester");
		createDefectTester.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				Class[] argumentTypes = {String.class, Tester.class, LifeCycleStep.class};
				WorkerManager.createWorker(WorkerManager.WorkerType.TESTER, operationMode, argumentTypes, factoryId, new DefectTester(), LifeCycleStep.TESTED_COMPLETENESS);
			}
		});
		Button createLogisticsWorker = new Button("Create Logistics Worker");
		createLogisticsWorker.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				WorkerManager.createWorker(WorkerManager.WorkerType.LOGISTICS, operationMode, factoryId);
			}
		});

		Button workerOverview = new Button("Worker Overview");
		workerOverview.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				new WorkersDialog().show();
			}
		});
		Button createOrder = new Button("New Order");
		createOrder.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				new CreateOrderDialog(operationMode, factoryId).show();
			}
		});

		hbox.getChildren().addAll(createProducer, createAssemblyWorker, createCompletnessTester, createDefectTester, createLogisticsWorker,
				new Separator(Orientation.VERTICAL),
				workerOverview, createOrder);

		border.setTop(hbox);

		HBox centerBox = new HBox();
		centerBox.setAlignment(Pos.CENTER);
		centerBox.setPadding(new Insets(10, 12, 10, 12));
		centerBox.setSpacing(10);

		final ListView<Part> parts = new ListView<Part>();
		parts.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		parts.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent mouseEvent) {
				if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
					PartDialog dialog = new PartDialog(parts.getSelectionModel().getSelectedItems().get(0));
					dialog.show();
				}
			}
		});
		parts.setCellFactory(new PartCellRender());
		final DataProvider<Part> partProvider = getPartDataProvider();
		partProvider.bind(parts);
		VBox partsBox = new VBox();
		partsBox.setSpacing(10);
		partsBox.setFillWidth(true);
		Label label = new Label("Parts");
		label.setFont(new Font("Arial", 18));
		partsBox.getChildren().addAll(label, parts);

		centerBox.getChildren().add(partsBox);

		final ListView<Computer> computers = new ListView<Computer>();
		computers.setCellFactory(new ComputerCellRenderer());
		computers.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent mouseEvent) {
				if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
					ComputerDialog dialog = new ComputerDialog(computers.getSelectionModel().getSelectedItems().get(0));
					dialog.show();
				}
			}
		});
		final DataProvider<Computer> computerProvider = getComputerStorageDataProvider();
		computerProvider.bind(computers);
		VBox computersBox = new VBox();
		computersBox.setSpacing(10);
		computersBox.setFillWidth(true);
		Label label1 = new Label("Internal Stock");
		label1.setFont(new Font("Arial", 18));
		computersBox.getChildren().addAll(label1, computers);
		centerBox.getChildren().add(computersBox);

		final ListView<Order> orders = new ListView<Order>();
		orders.setCellFactory(new OrderCellRenderer());
		orders.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent mouseEvent) {
				if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
					new OrderDialog(orders.getSelectionModel().getSelectedItems().get(0), operationMode, factoryId, "xvsm://localhost:4242");
				}
			}
		});
		final DataProvider<Order> orderProvider = getOrderDataProvider();
		orderProvider.bind(orders);
		VBox ordersBox = new VBox();
		ordersBox.setSpacing(10);
		ordersBox.setFillWidth(true);
		Label label2 = new Label("Orders");
		label2.setFont(new Font("Arial", 18));
		ordersBox.getChildren().addAll(label2, orders);
		centerBox.getChildren().add(ordersBox);

		border.setCenter(centerBox);

		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				//shutdown the dataproviders
				partProvider.shutdown();
				computerProvider.shutdown();
				orderProvider.shutdown();
			}
		});


		HBox bottomBox = new HBox();
		bottomBox.setAlignment(Pos.CENTER_LEFT);
		bottomBox.setPadding(new Insets(15, 12, 15, 12));
		bottomBox.setSpacing(10);
		bottomBox.setStyle("-fx-background-color: #336699");
		bottomBox.getChildren().add(new Label("SBC COMA - ManagementGUI, 2011"));
		border.setBottom(bottomBox);

		stage.show();
	}

	private DataProvider<Part> getPartDataProvider() {
		if (operationMode == WorkerManager.Mode.SPACE)
			return new SpacePartDataProvider("xvsm://localhost:4242", factoryId + "_" + Coma.PARTS_CONTAINER);
		else if (operationMode == WorkerManager.Mode.RMI)
			return new RMIPartDataProvider(factoryId);
		else
			throw new IllegalStateException();
	}

	private DataProvider<Computer> getComputerStorageDataProvider() {
		if (operationMode == WorkerManager.Mode.SPACE)
			return new SpaceComputerDataProvider("xvsm://localhost:4242", factoryId + "_" + Coma.COMPUTER_CONTAINER);
		else if (operationMode == WorkerManager.Mode.RMI)
			return new RMIComputerDataProvider(factoryId, Coma.COMPUTER_CONTAINER);
		else
			throw new IllegalStateException();
	}

	private DataProvider<Order> getOrderDataProvider() {
		if (operationMode == WorkerManager.Mode.SPACE)
			return new SpaceOrderDataProvider("xvsm://localhost:4242", factoryId + "_" + Coma.ORDER_CONTAINER);
		else if (operationMode == WorkerManager.Mode.RMI)
			return new RMIOrderDataProvider(factoryId);
		else
			throw new IllegalStateException();
	}
}
